#pragma once
# include <vector>
# include <thread>
# include <shared_mutex>
# include <atomic>

class MainWindow;
class ShowRemoteWindow;
class AudioCapture;
class VideoCapture;
class AudioEncoder;
class VideoEncoder;
class VideoDecoder;
class Timer;
class SaveFileFilter;
class GetDataFilter;
class Client;
class QString;
class MessageHandle;

class App {
	friend class MessageHandle;
public:
	App();

	int runWindow(int argc, char* argv[]);

	~App();
private:
	MainWindow* m_window = nullptr;
	ShowRemoteWindow* m_remote_window = nullptr;

	VideoCapture* m_video_capture = nullptr;
	AudioCapture* m_audio_capture = nullptr;
	std::vector<VideoCapture*>* m_video_capture_vector = nullptr;
	std::vector<AudioCapture*>* m_audio_capture_vector = nullptr;
	std::thread* m_main_thread = nullptr;
	std::shared_mutex* m_mutex = nullptr;
	Timer* m_fps_control;
	VideoEncoder* m_video_encoder = nullptr;
	VideoDecoder* m_video_decoder = nullptr;
	AudioEncoder* m_audio_encoder = nullptr;

	SaveFileFilter* m_save_file_filter = nullptr;
	GetDataFilter* m_get_data_filter = nullptr;
	int m_fps = 60;
	std::atomic<bool> m_main_thread_alive = false;

	std::atomic<bool> m_ui_state = false;

	Client* m_server = nullptr;
	MessageHandle* m_messageHandle = nullptr;
	std::atomic<int> m_connect_conv = 0;

	uint8_t* m_decode_buffer = nullptr;
	size_t m_decode_buffer_size = 0;

	void createDecodeBuffer(size_t _size);

	void onRemoteVideoFrame(uint8_t* _data, size_t _size);

	uint8_t* getEncodeContext(size_t& _size) const;

	void initVideoEncoder(int _width, int _height, int _fps, int _bit_rate);

	void initAudioEncoder(int _sample_rate, int _bit_rate);

	void initVideoDecoder(uint8_t* _video_encoder_ctx);

	void onUiCreateCallback();

	void onScreenCallback(int _videoVectorIndex, int* _videoCaptureWidthPtr, int* _videoCaptureHeightPtr);

	void onScreenStopCallback();

	const char * onRecordCallback(const char* _saveFileName);

	void onRecordStopCallbcak();

	void onConnectCallback(short _port);

	void onMessageInputCallback(const QString& _message);

	bool serverOnMessage(int _conv, char* _key, std::string _payload, char* _res_key, char* _response);
	bool serverOnConnected(unsigned int conv);
	bool serverOnClosed(unsigned int conv);

	void closeWindow();

	void runMainThread();

	void stopMainThread();

	void mainFunc();

	void log(const QString &_message);
};
